package com.netstar.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.RemoteViews;

import com.netstar.AppPreferences;
import com.netstar.R;
import com.netstar.library.NetStarApplication;
import com.netstar.message.MessageManager;
import com.netstar.process.ProcessInfo;
import com.netstar.process.ProcessListener;
import com.netstar.process.ProcessWatcher;
import com.netstar.request.DataRequest;
import com.netstar.request.HttpRequest;
import com.netstar.ui.activity.NetStarActivity;
import com.netstar.util.ContextUtils;
import com.netstar.util.EvtLog;
import com.netstar.util.RequestUtils;
import com.netstar.util.Utils;
import com.netstar.xmlparser.ServerChannelHelper;

public class NetService extends Service {

	private static final String TAG = "NetService";

	/**
	 * This can cause a 30 seconds error, since now we do not care it.
	 */
	private static final long UPDATE_TIMER_FREQUECY = 30 * 1000;
	private static final long UPDATE_CHANNEL_NETWORK_FREQUECY = 30 * 1000;
	private static final long UPDATE_APP_NETWORK_FREQUECY = 5 * 1000;
	private static final long UPDATE_NOTIFICATION_FREQUECY = 60 * 1000;
	private static final long UPDATE_SYNC_FREQUECY = 1 * 60 * 60 * 1000;
	/**
	 * Action for a event when the visibility of statusbar changed. The boolean
	 * type for key 'show' will be passed as an extra in the intent.
	 */
	public static final String EVENT_SHOW_IN_STATUSBAR_CHANGED = "event_show_in_statusbar";
	private String mLastConnectedSSID = null;
	private boolean mLastWifiOn = false;
	private boolean mLastMobileWifiOn = false;
	private boolean mLastUnicomWifiOn = false;
	private boolean mLastTelecomWifiOn = false;
	private long mTimeMobile = 0;
	private long mTimeWifi = 0;
	private long mTimeWifiMobile = 0;
	private long mTimeWifiUnicom = 0;
	private long mTimeWifiTelecom = 0;
	private long mGPRSStartedTime;
	private long mWifiStarteAt;
	private long mWifiMobileStartedAt;
	private long mUnicomStartedAt;
	private long mTelecomStartedAt;
	private int mNetworkFlag = FLAG_NONE;
	private static final int FLAG_NONE = -1;
	private static final int FLAG_MOBILE = 1;
	private static final int FLAG_WIFI = 2;
	private static final int FLAG_WIFI_MOBILE = 3;
	private static final int FLAG_WIFI_UNICOM = 4;
	private static final int FLAG_WIFI_TELECOM = 5;
	private String mCurrentChannel;
	private WifiManager mWifiManager;
	private AppPreferences mPreferences;
	private SharedPreferences mDefaultPreferences;
	private NotificationManager mNotificationManager;
	private HashMap<String, ChannelInfo> mChannelInfos;
	private boolean mNotificationInited;
	private int mNetworkChangedCount = 0;
	private BroadcastReceiver mNetworkReceiver;
	private BroadcastReceiver mChannelUpdateReceiver;

	private void resetOthers(String currentChannel) {
		HashMap<String, ChannelInfo> infos = mChannelInfos;
		Set<String> keySet = infos.keySet();
		for (String key : keySet) {
			if (!currentChannel.equals(key)) {
				infos.get(key).reset();
			}
		}
	}

	private static final int ID_NOTIFICATION = 1227;

	private Notification mNotification;

	private ProcessWatcher mProcessWatcher;

	@Override
	public void onCreate() {
		super.onCreate();

		mPreferences = AppPreferences.getInstance(this);
		mDefaultPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
		mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

		mChannelInfos = new HashMap<String, ChannelInfo>();
		mChannelInfos.put("CMCC", new ChannelInfo("CMCC"));
		mChannelInfos.put("ChinaUnicom", new ChannelInfo("ChinaUnicom"));
		mChannelInfos.put("ChinaNet", new ChannelInfo("ChinaNet"));
		mChannelInfos.put("WIFI", new ChannelInfo("WIFI"));

		if (mDefaultPreferences.getBoolean(getString(R.string.key_show_in_statusbar), true)) {
			// Show notification in status bar immediately when the application
			// started, not a delay of 2s.
			showNotificationIfNecessary();
		}

		registerProcessWatcher();

		registerReceivers();

		new MessageManager(this).blockMessage();

		mUpdateHandler.sendEmptyMessage(0);

		mAppNetworkDataHandler.sendEmptyMessageDelayed(0, 1000);

		mNotificationHandler.sendEmptyMessageDelayed(0, 2000);

		mSyncServerHandler.sendEmptyMessageDelayed(0, 8000);

		postDataAlarm();
	}

	private void registerProcessWatcher() {
		mProcessWatcher = ProcessWatcher.getDefault(this);
		mProcessWatcher.setProcessListener(new ProcessListener() {

			@Override
			public void onProcessStopped(final ProcessInfo info) {
				EvtLog.w(TAG, "onProcessStopped " + info.toString());
				mNotificationManager.cancel(info.uid);
			}

			@Override
			public void onProcessStarted(final ProcessInfo info) {
				Notification noti = new Notification(
						R.drawable.notification_icon, getString(R.string.noti_new_message), System.currentTimeMillis());
				noti.defaults = Notification.DEFAULT_SOUND;
				Intent intent = new Intent(NetService.this, NetStarActivity.class);
				intent.putExtra("tab", 1);
				// TODO
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				noti.flags = Notification.FLAG_AUTO_CANCEL;
				String[] appNames = info.appNames;
				noti.setLatestEventInfo(getApplicationContext(),
						(appNames.length > 1 ? Arrays.toString(info.appNames) : appNames[0]),
						getString(R.string.noti_content_gprs_closed),
						PendingIntent.getActivity(NetService.this, 0, intent, 0));
				mNotificationManager.notify(info.uid, noti);
			}
		});
		Cursor cursor = NetStarApplication.getDatabase().rawQuery("SELECT _uid FROM blocked_apps", null);
		while (cursor.moveToNext()) {
			mProcessWatcher.watch(cursor.getInt(cursor.getColumnIndex("_uid")));
		}
		cursor.close();
		mProcessWatcher.startWatch();
		if (!mDefaultPreferences.getBoolean(getString(R.string.key_show_warning_in_statusbar), true)) {
			mProcessWatcher.pause();
		}
	}

	// private SmsReceiver mSmsReceiver = new SmsReceiver();

	private void postDataAlarm() {
		HashMap<String, String> params = new HashMap<String, String>();
		params.put("imei", ContextUtils.getDeviceID(NetService.this));
		String loggedInPhone = mPreferences.getLoggedInPhone();
		params.put("phone",
				loggedInPhone.length() > 0 ? loggedInPhone : ContextUtils.getTelephoneNumber(NetService.this));
		params.put("dataAlarm", mDefaultPreferences.getString(getString(R.string.key_mobile_data), "100"));
		EvtLog.i(TAG, "post alarm data " + params.toString());
		RequestUtils.recordDataAlarm(params);
	}

	private static final int UPDATE_NONE = -1;
	private static final int UPDATE_ING = 0;
	private static final int UPDATE_SUCCEEDED = 1;
	private static final int UPDATE_FAILED = 2;
	private int mLastUpdateStatus = UPDATE_NONE;

	private Handler mUpdateHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			checkUpdate();
		}
	};

	private void checkUpdate() {
		if (!mPreferences.isLogin()) {
			return;
		}

		mLastUpdateStatus = UPDATE_ING;
		final String nowMonth = Utils.getNowInMonth();
		new DataRequest() {

			@Override
			public String getPath() {
				return "main/flow-record-by-date.action";
			}

			@Override
			public String getMethod() {
				return HttpRequest.GET;
			}

			@Override
			public HashMap<String, String> getData() {
				HashMap<String, String> params = new HashMap<String, String>();
				params.put("fromdate", nowMonth + "-01");
				params.put("enddate", Utils.getLastDayOfMonth(nowMonth));
				params.put("imei", ContextUtils.getDeviceID(NetService.this));
				params.put("phone", mPreferences.getLoggedInPhone());
				return params;
			}

			@Override
			public void onFail(String msg) {
				mLastUpdateStatus = UPDATE_FAILED;

				/*
				 * If the request failed, send request again and again.
				 */
				mUpdateHandler.sendEmptyMessageDelayed(0, 5 * 60 * 1000);
			}

			@Override
			public void onSuccess(String data) {
				mLastUpdateStatus = UPDATE_SUCCEEDED;
				ArrayList<ServerChannelHelper.ServerChannelItem> list = ServerChannelHelper.parse(data);
				Utils.saveListToFile(list, nowMonth);

				mNotificationHandler.removeMessages(0);
				mNotificationHandler.sendEmptyMessage(0);
				sendBroadcast(new Intent("update_history_achieved"));
			}
		}.makeRequest();
	}

	private void notifySyncServerStart() {
		Intent intent = new Intent("noti_sync_start");
		sendBroadcast(intent);
	}

	private void notifySyncServerCompleted() {
		Intent intent = new Intent("noti_sync_end");
		sendBroadcast(intent);
	}

	private Handler mSyncServerHandler = new Handler() {

		private int mChannelCount;
		private int mChannelFailed;
		private int mChannelSucceed;

		private int mAppCount;
		private int mAppFailed;
		private int mAppSucceed;

		private void check() {
			if (mChannelFailed + mChannelSucceed == mChannelCount && mAppFailed + mAppSucceed == mAppCount) {
				notifySyncServerCompleted();
				if (mChannelSucceed + mAppSucceed != 0) {
					// There is at least one request succeeded, so update the
					// day list.
					mUpdateHandler.removeMessages(0);
					mUpdateHandler.sendEmptyMessage(0);
				}
			}
		}

		@Override
		public void handleMessage(Message msg) {
			notifySyncServerStart();

			mChannelFailed = 0;
			mChannelSucceed = 0;
			mAppFailed = 0;
			mAppSucceed = 0;

			final String today = Utils.getNowInDay();
			final SQLiteDatabase db = NetStarApplication.getDatabase();

			Cursor channelCursor = db.rawQuery(
					"SELECT * FROM view_channel WHERE _sync = 0 AND _day != '" + today + "'", null);
			mChannelCount = channelCursor.getCount();

			Cursor appCursor = db.rawQuery(
					"SELECT _received, _sent, _day, _name FROM view_day WHERE _sync = 0 AND _day != '" + today + "'",
					null);
			mAppCount = appCursor.getCount();

			if (mChannelCount == 0 && mAppCount == 0) {
				notifySyncServerCompleted();
			}

			int indexGPRSData = channelCursor.getColumnIndex("_3g_gprs_d");
			int indexCMCCData = channelCursor.getColumnIndex("_cmcc_d");
			int indexUnicomData = channelCursor.getColumnIndex("_unicom_d");
			int indexTelecomData = channelCursor.getColumnIndex("_china_net_d");
			int indexWifiData = channelCursor.getColumnIndex("_wifi_d");
			int indexDay = channelCursor.getColumnIndex("_day");
			int indexGPRSTime = channelCursor.getColumnIndex("_3g_gprs_t");
			int indexCMCCTime = channelCursor.getColumnIndex("_cmcc_t");
			int indexUnicomTime = channelCursor.getColumnIndex("_unicom_t");
			int indexTelecomTime = channelCursor.getColumnIndex("_china_net_t");
			int indexWifiTime = channelCursor.getColumnIndex("_wifi_t");
			for (int i = 0; i < mChannelCount; i++) {
				channelCursor.moveToPosition(i);
				final String day = channelCursor.getString(indexDay);
				HashMap<String, String> params = new HashMap<String, String>();
				params.put("gprswificount", String.valueOf(channelCursor.getLong(indexGPRSData)));
				params.put("mobwificount", String.valueOf(channelCursor.getLong(indexCMCCData)));
				params.put("ltwificount", String.valueOf(channelCursor.getLong(indexUnicomData)));
				params.put("telwificount", String.valueOf(channelCursor.getLong(indexTelecomData)));
				params.put("privatewificount", String.valueOf(channelCursor.getLong(indexWifiData)));
				params.put("cdate", day);
				params.put("gprswifitime", String.valueOf(indexGPRSTime));
				params.put("mobwifitime", String.valueOf(channelCursor.getLong(indexCMCCTime)));
				params.put("ltwifitime", String.valueOf(channelCursor.getLong(indexUnicomTime)));
				params.put("telwifitime", String.valueOf(channelCursor.getLong(indexTelecomTime)));
				params.put("privatewifitime", String.valueOf(channelCursor.getLong(indexWifiTime)));
				params.put("imei", ContextUtils.getDeviceID(NetService.this));
				String loggedInPhone = mPreferences.getLoggedInPhone();
				params.put("phone",
						loggedInPhone.length() > 0 ? loggedInPhone : ContextUtils.getTelephoneNumber(NetService.this));

				RequestUtils.recordChannel(params, new RequestUtils.RecordChannelCB() {

					@Override
					public void onFail() {
						mChannelFailed++;
						check();
					}

					@Override
					public void onSuccess() {
						ContentValues values = new ContentValues();
						values.put("_sync", "1");
						db.beginTransaction();
						try {
							db.update("channel_day_stat", values, "_day = '" + day + "'", null);
							db.update("net_timer", values, "_day = '" + day + "'", null);
							db.setTransactionSuccessful();
						} finally {
							db.endTransaction();
						}

						mChannelSucceed++;
						check();
					}
				});
			}
			channelCursor.close();

			int iDay = appCursor.getColumnIndex("_day");
			int iName = appCursor.getColumnIndex("_name");
			int iReceived = appCursor.getColumnIndex("_received");
			int iSent = appCursor.getColumnIndex("_sent");
			for (int i = 0; i < mAppCount; i++) {
				appCursor.moveToPosition(i);
				final String day = appCursor.getString(iDay);
				HashMap<String, String> params = new HashMap<String, String>();
				params.put("cdate", day);
				params.put("name", appCursor.getString(iName));
				params.put("flowcount", String.valueOf(appCursor.getLong(iReceived) + appCursor.getLong(iSent)));
				params.put("flowtime", "0");
				String loggedInPhone = mPreferences.getLoggedInPhone();
				params.put("phone",
						loggedInPhone.length() > 0 ? loggedInPhone : ContextUtils.getTelephoneNumber(NetService.this));
				params.put("imei", ContextUtils.getDeviceID(NetService.this));
				RequestUtils.recordSoftware(params, new RequestUtils.RecordChannelCB() {

					@Override
					public void onFail() {
						mAppFailed++;
						check();
					}

					@Override
					public void onSuccess() {
						ContentValues values = new ContentValues();
						values.put("_sync", "1");
						db.update("apps_day_stat", values, "_day = '" + day + "'", null);
						mAppSucceed++;
						check();
					}
				});
			}
			appCursor.close();

			sendEmptyMessageDelayed(0, UPDATE_SYNC_FREQUECY);
		}
	};

	private void showNotificationIfNecessary() {
		if (mNotificationInited) {
			mNotificationManager.notify(ID_NOTIFICATION, mNotification);
			return;
		}
		mNotification = new Notification(
				R.drawable.notification_icon, getString(R.string.noti_app_title), System.currentTimeMillis());
		final Notification noti = mNotification;
		noti.flags = Notification.FLAG_ONGOING_EVENT;
		noti.contentView = new RemoteViews(getPackageName(), R.layout.notification_app_status);
		// TODO 需要判断进程是否打开
		Intent intent = new Intent(this, NetStarActivity.class);
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
		noti.contentIntent = pendingIntent;
		mNotificationManager.notify(ID_NOTIFICATION, noti);

		mNotificationInited = true;
	}

	private void hideNotification() {
		if (!mNotificationInited) {
			return;
		}
		mNotificationManager.cancel(ID_NOTIFICATION);
	}

	private Handler mNotificationHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			if (mDefaultPreferences.getBoolean(getString(R.string.key_show_in_statusbar), true)) {
				showNotificationIfNecessary();
				updateNotification();
				sendEmptyMessageDelayed(0, UPDATE_NOTIFICATION_FREQUECY);
			}
		}
	};

	private void updateNotification() {
		final SQLiteDatabase db = NetStarApplication.getDatabase();
		final String channel = mDefaultPreferences.getString(getString(R.string.key_plate), "3G/GPRS 流量");
		int index = channel.indexOf(" ");
		String s = "3G/GPRS";
		if (-1 != index) {
			s = channel.substring(0, index);
		}
		String keyTotalMB = getString(s.equals("3G/GPRS") ? R.string.key_mobile_data : R.string.key_public_data);
		long settingsMBs = Long.parseLong(mDefaultPreferences.getString(keyTotalMB, "100"));
		long settingsBytes = settingsMBs << 20;
		final String month = Utils.getNowInMonth();

		final Cursor cursor = db.rawQuery("SELECT * FROM view_channel WHERE _day LIKE '" + month
				+ "%' ORDER BY _day DESC LIMIT 1", null);

		ServerChannelHelper.ServerChannelItem item = null;
		if (cursor.moveToNext()) {
			item = parseItem(cursor);
		}
		cursor.close();

		final int mncId = ContextUtils.getMncIdentifier(this);

		// 这个月免流量的程序的3G/GPRS上行和下行流量游标
		final Cursor excludedCursor = db.rawQuery("SELECT _g_sent, _g_received FROM view_day WHERE _day LIKE '" + month
				+ "%' AND _mnc_id = " + mncId, null);

		/*
		 * 这个月应扣除的3G/GPRS流量
		 */
		long monthExcludedBytesForGPRS = 0;

		while (excludedCursor.moveToNext()) {
			final long record = excludedCursor.getLong(excludedCursor.getColumnIndex("_g_sent"))
					+ excludedCursor.getLong(excludedCursor.getColumnIndex("_g_received"));
			monthExcludedBytesForGPRS += record;
		}
		excludedCursor.close();

		long dataMobile = 0;
		long timeMobile = 0;
		long dataCMCC = 0;
		long timeCMCC = 0;
		// long dataUnicom = 0;
		// long timeUnicom = 0;
		long dataTelecom = 0;
		long timeTelecom = 0;
		long dataWifi = 0;
		long timeWifi = 0;

		ArrayList<ServerChannelHelper.ServerChannelItem> list = Utils.parseFileToList(month);
		if (null != list) {
			for (ServerChannelHelper.ServerChannelItem serverChannelItem : list) {
				dataMobile += serverChannelItem.dataMobile;
				timeMobile += serverChannelItem.timeMobile;
				dataCMCC += serverChannelItem.dataCMCC;
				timeCMCC += serverChannelItem.timeCMCC;
				// dataUnicom = serverChannelItem.dataUnicom;
				// timeUnicom = serverChannelItem.timeUnicom;
				dataTelecom += serverChannelItem.dataTelecom;
				timeTelecom += serverChannelItem.timeTelecom;
				dataWifi += serverChannelItem.dataWifi;
				timeWifi += serverChannelItem.timeWifi;
			}
		}

		long currBytes = 0;
		if (null == list) {
			Cursor bytesCursor = db.rawQuery("SELECT SUM(" + Utils.channelToCol(channel)
					+ ") AS _bytes FROM channel_day_stat WHERE _day LIKE '" + month + "%'", null);

			if (bytesCursor.moveToNext()) {
				currBytes = bytesCursor.getLong(bytesCursor.getColumnIndex("_bytes"));
			}
			bytesCursor.close();
		} else {
			if (channel.startsWith("3G/GPRS")) {
				currBytes = dataMobile;
				if (null != item) {
					currBytes += item.dataMobile;
				}
			} else if (channel.startsWith("CMCC")) {
				currBytes = dataCMCC;
				if (null != item) {
					currBytes += item.dataCMCC;
				}
			} else if (channel.startsWith("ChinaNet")) {
				currBytes = dataTelecom;
				if (null != item) {
					currBytes += dataTelecom;
				}
			}
		}
		if (channel.startsWith("3G/GPRS")) {
			currBytes -= monthExcludedBytesForGPRS;
		}

		float progress = (float) (currBytes * 100) / settingsBytes;

		final Notification notification = mNotification;
		RemoteViews views = notification.contentView;

		if (currBytes > settingsBytes) {
			views.setTextViewText(R.id.noti_desc, s + "本月使用流量已超过上限" + settingsMBs + "MB");
		} else {
			views.setTextViewText(R.id.noti_desc,
					s + "已使用" + Utils.toMBLength(currBytes) + "M，剩余" + Utils.toMBLength((settingsBytes - currBytes))
							+ "M");
		}
		views.setProgressBar(R.id.noti_progress, 100, (int) progress, false);
		mNotificationManager.notify(ID_NOTIFICATION, notification);
	}

	public static ServerChannelHelper.ServerChannelItem parseItem(Cursor cursor) {
		ServerChannelHelper.ServerChannelItem item = new ServerChannelHelper.ServerChannelItem();
		item.dataMobile = cursor.getLong(0);
		item.dataCMCC = cursor.getLong(1);
		item.dataUnicom = cursor.getLong(2);
		item.dataTelecom = cursor.getLong(3);
		item.dataWifi = cursor.getLong(4);
		item.day = cursor.getString(5);
		item.timeMobile = cursor.getLong(6);
		item.timeCMCC = cursor.getLong(7);
		item.timeUnicom = cursor.getLong(8);
		item.timeTelecom = cursor.getLong(9);
		item.timeWifi = cursor.getLong(10);
		return item;
	}

	private void registerReceivers() {
		if (null == mNetworkReceiver) {
			mNetworkReceiver = new BroadcastReceiver() {

				@Override
				public void onReceive(Context context, Intent intent) {
					final NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
					final NetworkInfo.State state = networkInfo.getState();
					if (state != NetworkInfo.State.CONNECTED && state != NetworkInfo.State.DISCONNECTED) {
						return;
					}
					mNetworkChangedCount++;
					final boolean isFirst = mNetworkChangedCount == 1;

					// Update before mNetworkFlag changes
					if (!isFirst) {
						mAppNetworkDataHandler.removeMessages(0);
						syncAppDataInDay(false);
						mAppNetworkDataHandler.sendEmptyMessageDelayed(0, UPDATE_APP_NETWORK_FREQUECY);
					}

					final int type = networkInfo.getType();
					final long currMillis = System.currentTimeMillis();

					if (NetworkInfo.State.CONNECTED == state) {
						// check last update status
						if (UPDATE_FAILED == mLastUpdateStatus) {
							mUpdateHandler.removeMessages(0);
							mUpdateHandler.sendEmptyMessage(0);
						}

						if (ConnectivityManager.TYPE_MOBILE == type) {
							mGPRSStartedTime = currMillis;
							mNetworkFlag = FLAG_MOBILE;
							resetOthers("");
						} else {
							WifiInfo info = mWifiManager.getConnectionInfo();
							final String currentSSID = info.getSSID();
							final String lastSSID = mLastConnectedSSID;
							if (null != currentSSID) {
								mLastConnectedSSID = currentSSID;
								if (currentSSID.equals("CMCC")) {
									resetOthers("CMCC");
									ChannelInfo channel = mChannelInfos.get("CMCC");
									channel.lastBytes = Utils.getWifiBytes();
									if (mLastMobileWifiOn && lastSSID.equals("CMCC")) {
										channel.newlyConnected = false;
										Log.i(TAG, "the cm wifi is still on");
									} else {
										mWifiMobileStartedAt = currMillis;
										channel.newlyConnected = true;
										Log.e(TAG, "start count time for cm...");
									}
									mCurrentChannel = "CMCC";
									mLastMobileWifiOn = true;
									mNetworkFlag = FLAG_WIFI_MOBILE;
								} else if (currentSSID.equals("ChinaUnicom")) {
									resetOthers("ChinaUnicom");
									ChannelInfo channel = mChannelInfos.get("ChinaUnicom");
									channel.lastBytes = Utils.getWifiBytes();
									if (mLastUnicomWifiOn && lastSSID.equals("ChinaUnicom")) {
										channel.newlyConnected = false;
										Log.i(TAG, "the un wifi is still on...");
									} else {
										mUnicomStartedAt = currMillis;
										channel.newlyConnected = true;
										Log.e(TAG, "start count time for un...");
									}
									mCurrentChannel = "ChinaUnicom";
									mLastUnicomWifiOn = true;
									mNetworkFlag = FLAG_WIFI_UNICOM;
								} else if (currentSSID.equals("ChinaNet")) {
									resetOthers("ChinaNet");
									ChannelInfo channel = mChannelInfos.get("ChinaNet");
									channel.lastBytes = Utils.getWifiBytes();
									if (mLastTelecomWifiOn && lastSSID.equals("ChinaNet")) {
										channel.newlyConnected = false;
										Log.i(TAG, "the ch wifi is still on...");
									} else {
										mTelecomStartedAt = currMillis;
										channel.newlyConnected = true;
										Log.e(TAG, "start count time for ch");
									}
									mCurrentChannel = "ChinaNet";
									mLastTelecomWifiOn = true;
									mNetworkFlag = FLAG_WIFI_TELECOM;
								} else {
									resetOthers("WIFI");
									ChannelInfo channel = mChannelInfos.get("WIFI");
									channel.lastBytes = Utils.getWifiBytes();
									if (mLastWifiOn && lastSSID.equals(currentSSID)) {
										channel.newlyConnected = false;
										Log.i(TAG, "the last wifi is still on, ssid is " + currentSSID);
									} else {
										mWifiStarteAt = currMillis;
										channel.newlyConnected = true;
										Log.e(TAG, "start count wifi time for ssid: " + currentSSID);
									}
									mCurrentChannel = "WIFI";
									mLastWifiOn = true;
									mNetworkFlag = FLAG_WIFI;
								}
							}
						}
					} else {
						if (ConnectivityManager.TYPE_MOBILE == type) {
							mTimeMobile += currMillis - mGPRSStartedTime;
							resetOthers("");
						} else {
							switch (mNetworkFlag) {
								case FLAG_WIFI_MOBILE:
									mLastMobileWifiOn = false;
									mTimeWifiMobile += currMillis - mWifiMobileStartedAt;
									ChannelInfo channel1 = mChannelInfos.get("CMCC");
									channel1.lastBytes = Utils.getWifiBytes();
									channel1.newlyConnected = false;
									resetOthers("CMCC");
									break;
								case FLAG_WIFI_UNICOM:
									mLastUnicomWifiOn = false;
									mTimeWifiUnicom += currMillis - mUnicomStartedAt;
									ChannelInfo channel2 = mChannelInfos.get("ChinaUnicom");
									channel2.lastBytes = Utils.getWifiBytes();

									channel2.newlyConnected = false;
									resetOthers("ChinaUnicom");
									break;
								case FLAG_WIFI_TELECOM:
									mLastTelecomWifiOn = false;
									mTimeWifiTelecom += currMillis - mTelecomStartedAt;
									ChannelInfo channel3 = mChannelInfos.get("ChinaNet");
									channel3.lastBytes = Utils.getWifiBytes();
									channel3.newlyConnected = false;
									resetOthers("ChinaNet");
									break;
								case FLAG_WIFI:
									mLastWifiOn = false;
									mTimeWifi += currMillis - mWifiStarteAt;
									ChannelInfo channel4 = mChannelInfos.get("WIFI");
									channel4.lastBytes = Utils.getWifiBytes();
									channel4.newlyConnected = false;
									resetOthers("WIFI");
									break;
								default:
									break;
							}
						}
						mNetworkFlag = FLAG_NONE;
					}

					mChannelTimerHandler.removeMessages(0);
					updateChannelTimer(isFirst);
					mChannelDataHandler.removeMessages(0);
					updateChannelData(isFirst);
				}
			};
		}
		IntentFilter filter = new IntentFilter();
		filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
		registerReceiver(mNetworkReceiver, filter);

		if (null == mChannelUpdateReceiver) {
			mChannelUpdateReceiver = new BroadcastReceiver() {

				@Override
				public void onReceive(Context context, Intent intent) {
					String action = intent.getAction();
					if (action.equals(EVENT_SHOW_IN_STATUSBAR_CHANGED)) {
						boolean show = intent.getBooleanExtra("show", true);
						if (show) {
							mNotificationHandler.removeMessages(0);
							mNotificationHandler.sendEmptyMessage(0);
						} else {
							hideNotification();
						}
					} else {
						mNotificationHandler.removeMessages(0);
						mNotificationHandler.sendEmptyMessage(0);
						if (action.equals("event_net_params_changed")) {
							int limited = intent.getIntExtra("gprs_limited", -1);
							if (limited > 0) {
								postDataAlarm();
							}
						}
					}
				}
			};
		}
		IntentFilter cFilter = new IntentFilter();
		cFilter.addAction("event_channel_updated");
		cFilter.addAction("event_net_params_changed");
		cFilter.addAction("event_logged_in");
		cFilter.addAction(EVENT_SHOW_IN_STATUSBAR_CHANGED);
		registerReceiver(mChannelUpdateReceiver, cFilter);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (null == intent) {
			stopSelf();
			return START_STICKY_COMPATIBILITY;
		}
		String cmd = intent.getStringExtra("cmd");
		EvtLog.i(TAG, "start command " + cmd);
		if ("boot".equals(cmd)) {
			/*
			 * We should sync the network statistics for the first time since
			 * boot.
			 */
			AppPreferences.getInstance(this).setBootTime(System.currentTimeMillis());
		} else if ("sync_app_network".equals(cmd)) {
			mAppNetworkDataHandler.removeMessages(0);
			mAppNetworkDataHandler.sendEmptyMessage(0);
		}
		return START_STICKY_COMPATIBILITY;
	}

	private final Handler mChannelTimerHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			updateChannelTimer(false);
		}
	};

	private void updateChannelTimer(boolean isFirst) {
		final long currMillis = System.currentTimeMillis();
		switch (mNetworkFlag) {
			case FLAG_WIFI:
				mTimeWifi = currMillis - mWifiStarteAt;
				mWifiStarteAt = currMillis;
				break;
			case FLAG_MOBILE:
				mTimeMobile = currMillis - mGPRSStartedTime;
				mGPRSStartedTime = currMillis;
				break;
			case FLAG_WIFI_MOBILE:
				mTimeWifiMobile = currMillis - mWifiMobileStartedAt;
				mWifiMobileStartedAt = currMillis;
				break;
			case FLAG_WIFI_UNICOM:
				mTimeWifiUnicom = currMillis - mUnicomStartedAt;
				mUnicomStartedAt = currMillis;
				break;
			case FLAG_WIFI_TELECOM:
				mTimeWifiTelecom = currMillis - mTelecomStartedAt;
				mTelecomStartedAt = currMillis;
				break;
			case FLAG_NONE:
				mTimeMobile = 0;
				mTimeWifi = 0;
				mTimeWifiMobile = 0;
				mTimeWifiUnicom = 0;
				mTimeWifiTelecom = 0;
				break;
		}
		String today = Utils.getNowInDay();
		SQLiteDatabase db = NetStarApplication.getDatabase();
		Cursor cursor = db.rawQuery("SELECT * FROM net_timer WHERE _day = '" + today + "'", null);
		if (cursor.moveToNext()) {
			long id = cursor.getLong(cursor.getColumnIndex("_id"));
			long gprs = cursor.getLong(cursor.getColumnIndex("_3g_gprs"));
			long cmcc = cursor.getLong(cursor.getColumnIndex("_cmcc"));
			long unicom = cursor.getLong(cursor.getColumnIndex("_unicom"));
			long telecom = cursor.getLong(cursor.getColumnIndex("_china_net"));
			long wifi = cursor.getLong(cursor.getColumnIndex("_wifi"));

			ContentValues values = new ContentValues();
			if (0 != mTimeMobile) {
				values.put("_3g_gprs", gprs + mTimeMobile);
			}
			if (0 != mTimeWifiMobile) {
				values.put("_cmcc", cmcc + mTimeWifiMobile);
			}
			if (0 != mTimeWifiUnicom) {
				values.put("_unicom", unicom + mTimeWifiUnicom);
			}
			if (0 != mTimeWifiTelecom) {
				values.put("_china_net", telecom + mTimeWifiTelecom);
			}
			if (0 != mTimeWifi) {
				values.put("_wifi", wifi + mTimeWifi);
			}

			if (values.size() > 0) {
				db.update("net_timer", values, "_id = " + id, null);
			}
		} else {
			// if (NetApplication.getApplicationStartDay().equals(today)) {
			// /*
			// * 该程序的启动时间与当前时间是同一天，因此这是当天的第一次时间统计
			// */
			ContentValues values = new ContentValues();
			values.put("_3g_gprs", mTimeMobile);
			values.put("_cmcc", mTimeWifiMobile);
			values.put("_unicom", mTimeWifiUnicom);
			values.put("_china_net", mTimeWifiTelecom);
			values.put("_wifi", mTimeWifi);
			values.put("_day", today);
			db.insert("net_timer", null, values);

			EvtLog.i(TAG, "insert {" + values.toString() + "} to TABLE net_timer");
			// } else {
			// /*
			// * 新的一天，统计清零，有UPDATE_TIMER_FREQUECY的误差
			// */
			// mTimeMobile = 0;
			// mTimeWifiMobile = 0;
			// mTimeWifiUnicom = 0;
			// mTimeWifiTelecom = 0;
			// mTimeWifi = 0;
			// ContentValues values = new ContentValues();
			// values.put("_day", today);
			// db.insert("net_timer", null, values);
			// }
		}
		cursor.close();

		sendBroadcast(new Intent("event_today_timer_updated"));
		if (mNetworkFlag != FLAG_NONE) {
			mChannelTimerHandler.sendEmptyMessageDelayed(0, UPDATE_TIMER_FREQUECY);
		} else {
			EvtLog.w(TAG, "no connected network, pause updating for net_timer");
		}
	}

	private final Handler mChannelDataHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			updateChannelData(false);
		}
	};

	private void updateChannelData(boolean isFirst) {
		final String currentChannel = mCurrentChannel;
		if (null != currentChannel) {
			if (!isFirst) {
				// 如果不是第一次更新，我们更新该channel的状态，因为如果是第一次更新，此channel已被填充
				ChannelInfo info = mChannelInfos.get(currentChannel);
				info.newlyConnected = false;
				info.lastBytes = Utils.getWifiBytes();
			}
		}
		final String today = Utils.getNowInDay();
		final SQLiteDatabase db = NetStarApplication.getDatabase();
		Cursor bootCursor = db.rawQuery("SELECT * FROM channel_day_stat WHERE _updated > " + mPreferences.getBootTime()
				+ " ORDER BY _id DESC LIMIT 1", null);
		if (bootCursor.moveToFirst()) {
			// 从设备重启到现在，更新过数据库，移动网络数据不会清零，但是WIFI可能清零
			long id = bootCursor.getLong(bootCursor.getColumnIndex("_id"));
			long gprs = bootCursor.getLong(bootCursor.getColumnIndex("_3g_gprs"));
			long gprsSinceBoot = bootCursor.getLong(bootCursor.getColumnIndex("_3g_gprs_s_boot"));
			long cmcc = bootCursor.getLong(bootCursor.getColumnIndex("_cmcc"));
			long unicom = bootCursor.getLong(bootCursor.getColumnIndex("_unicom"));
			long telecom = bootCursor.getLong(bootCursor.getColumnIndex("_china_net"));
			long wifi = bootCursor.getLong(bootCursor.getColumnIndex("_wifi"));
			long wifiLast = bootCursor.getLong(bootCursor.getColumnIndex("_wifi_last"));
			String day = bootCursor.getString(bootCursor.getColumnIndex("_day"));

			if (day.equals(today)) {
				// 今天的记录存在
				long gprsNow = Utils.getMobileBytes();
				long deltaGPRS = gprsNow - gprsSinceBoot;
				ContentValues values = new ContentValues();
				if (deltaGPRS > 0) {
					values.put("_3g_gprs", gprs + deltaGPRS);
					values.put("_3g_gprs_s_boot", gprsNow);
				} else if (deltaGPRS < 0) {
					values.put("_3g_gprs", gprs + gprsNow);
					values.put("_3g_gprs_s_boot", gprsNow);
				}

				final HashMap<String, ChannelInfo> infos = mChannelInfos;
				ChannelInfo channelCMCC = infos.get("CMCC");
				if (channelCMCC.newlyConnected) {
					if (isFirst) {
						// 程序一开始，检测到有CMCC-WIFI网络，UPDATE一下？
						long lastBytes = channelCMCC.lastBytes;
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_cmcc", cmcc + delta);
							values.put("_wifi_last", lastBytes);
						} else if (delta < 0) {
							values.put("_cmcc", cmcc + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					} else {
						// WIFI有个关闭的过程，现在又开了，流量清零，累加之
						long lastBytes = channelCMCC.lastBytes;
						if (lastBytes > 0) {
							// 有时候得到的wifi bytes 会是-1287这种
							values.put("_cmcc", cmcc + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				} else {
					long lastBytes = channelCMCC.lastBytes;
					if (lastBytes > 0 && !isFirst) {
						// WIFI 开了又关了，这个时候应该是最大流量值
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_cmcc", cmcc + delta);
							values.put("_wifi_last", lastBytes);
						} else if (delta < 0) {
							values.put("_cmcc", cmcc + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				}

				ChannelInfo channelUnicom = infos.get("ChinaUnicom");
				if (channelUnicom.newlyConnected) {
					if (isFirst) {
						// 程序一开始，检测到有ChinaUnicom-WIFI网络，UPDATE一下？
						long lastBytes = channelUnicom.lastBytes;
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_unicom", unicom + delta);
							values.put("_wifi_last", lastBytes);
						} else if (delta < 0) {
							values.put("_unicom", unicom + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					} else {
						// WIFI有个关闭的过程，现在又开了，流量清零，累加之
						long lastBytes = channelUnicom.lastBytes;
						if (lastBytes > 0) {
							values.put("_unicom", unicom + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				} else {
					long lastBytes = channelUnicom.lastBytes;
					if (lastBytes > 0 && !isFirst) {
						// WIFI 开了又关了，这个时候应该是最大流量值
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_unicom", unicom + delta);
							values.put("_wifi_last", lastBytes);
						} else if (delta < 0) {
							values.put("_unicom", unicom + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				}

				ChannelInfo channelTelecom = infos.get("ChinaNet");
				if (channelTelecom.newlyConnected) {
					if (isFirst) {
						// 程序一开始，检测到有ChinaNet-WIFI网络，UPDATE一下？
						long lastBytes = channelTelecom.lastBytes;
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_china_net", telecom + delta);
							values.put("_wifi_last", lastBytes);
						} else if (delta < 0) {
							values.put("_china_net", telecom + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					} else {
						// WIFI有个关闭的过程，现在又开了，流量清零，累加之
						long lastBytes = channelTelecom.lastBytes;
						if (lastBytes > 0) {
							values.put("_china_net", telecom + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				} else {
					long lastBytes = channelTelecom.lastBytes;
					if (lastBytes > 0 && !isFirst) {
						// WIFI 开了又关了，这个时候应该是最大流量值
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_china_net", telecom + delta);
							values.put("_wifi_last", lastBytes);
						} else if (delta < 0) {
							values.put("_china_net", telecom + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				}

				ChannelInfo channelWIFI = infos.get("WIFI");
				if (channelWIFI.newlyConnected) {
					if (isFirst) {
						// 程序一开始，检测到有WIFI网络，UPDATE一下？
						long lastBytes = channelWIFI.lastBytes;
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_wifi", wifi + delta);
							values.put("_wifi_last", lastBytes);
						} else if (delta < 0) {
							values.put("_wifi", wifi + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					} else {
						// WIFI有个关闭的过程，现在又开了，流量清零，累加之
						long lastBytes = channelWIFI.lastBytes;
						if (lastBytes > 0) {
							values.put("_wifi", wifi + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				} else {
					long lastBytes = channelWIFI.lastBytes;
					if (lastBytes > 0 && !isFirst) {
						// WIFI 开了又关了，这个时候应该是最大流量值
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_wifi", wifi + delta);
							values.put("_wifi_last", lastBytes);
						} else if (delta < 0) {
							values.put("_wifi", wifi + lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				}
				values.put("_updated", System.currentTimeMillis());
				db.update("channel_day_stat", values, "_id = " + id, null);
			} else {
				// 重启之后有更新数据库，但并不存在今天的流量统计
				long gprsNow = Utils.getMobileBytes();
				long deltaGPRS = gprsNow - gprsSinceBoot;
				ContentValues values = new ContentValues();
				if (deltaGPRS >= 0) {
					values.put("_3g_gprs", deltaGPRS);
				} else {
					values.put("_3g_gprs", gprsNow);
				}
				values.put("_3g_gprs_s_boot", gprsNow);

				final HashMap<String, ChannelInfo> infos = mChannelInfos;

				ChannelInfo channelWIFI = infos.get("WIFI");
				if (channelWIFI.newlyConnected) {
					if (isFirst) {
						// 考虑到这是新的一天，而且是今天第一次运行，可能程序挂掉很长时间，
						// 无法估算误差，流量重新计算
						long lastBytes = channelWIFI.lastBytes;
						if (lastBytes > 0) {
							values.put("_wifi", lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					} else {
						// 程序运行期间，WIFI有个关闭的过程，现在又开了，流量重新计算
						long lastBytes = channelWIFI.lastBytes;
						if (lastBytes > 0) {
							values.put("_wifi", lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				} else {
					long lastBytes = channelWIFI.lastBytes;
					if (lastBytes > 0) {
						// WIFI 开了又关了，这个时候应该是最大流量值
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_wifi", delta);
							values.put("_wifi_last", lastBytes);
						}
					}
				}

				ChannelInfo channelCMCC = infos.get("CMCC");
				if (channelCMCC.newlyConnected) {
					if (isFirst) {
						// 考虑到这是新的一天，而且是今天第一次运行，可能程序挂掉很长时间，
						// 无法估算误差，流量重新计算
						long lastBytes = channelCMCC.lastBytes;
						if (lastBytes > 0) {
							values.put("_cmcc", lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					} else {
						// 程序运行期间，WIFI有个关闭的过程，现在又开了，流量重新计算
						long lastBytes = channelCMCC.lastBytes;
						if (lastBytes > 0) {
							values.put("_cmcc", lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				} else {
					long lastBytes = channelCMCC.lastBytes;
					if (lastBytes > 0) {
						// WIFI 开了又关了，这个时候应该是最大流量值
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_cmcc", delta);
							values.put("_wifi_last", lastBytes);
						}
					}
				}

				ChannelInfo channelUnicom = infos.get("ChinaUnicom");
				if (channelUnicom.newlyConnected) {
					if (isFirst) {
						// 考虑到这是新的一天，而且是今天第一次运行，可能程序挂掉很长时间，
						// 无法估算误差，流量重新计算
						long lastBytes = channelUnicom.lastBytes;
						if (lastBytes > 0) {
							values.put("_unicom", lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					} else {
						// 程序运行期间，WIFI有个关闭的过程，现在又开了，流量重新计算
						long lastBytes = channelUnicom.lastBytes;
						if (lastBytes > 0) {
							values.put("_unicom", lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				} else {
					long lastBytes = channelUnicom.lastBytes;
					if (lastBytes > 0) {
						// WIFI 开了又关了，这个时候应该是最大流量值
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_unicom", delta);
							values.put("_wifi_last", lastBytes);
						}
					}
				}

				ChannelInfo channelChinaNet = infos.get("ChinaNet");
				if (channelChinaNet.newlyConnected) {
					if (isFirst) {
						// 考虑到这是新的一天，而且是今天第一次运行，可能程序挂掉很长时间，
						// 无法估算误差，流量重新计算
						long lastBytes = channelChinaNet.lastBytes;
						if (lastBytes > 0) {
							values.put("_china_net", lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					} else {
						// 程序运行期间，WIFI有个关闭的过程，现在又开了，流量重新计算
						long lastBytes = channelChinaNet.lastBytes;
						if (lastBytes > 0) {
							values.put("_china_net", lastBytes);
							values.put("_wifi_last", lastBytes);
						}
					}
				} else {
					long lastBytes = channelChinaNet.lastBytes;
					if (lastBytes > 0) {
						// WIFI 开了又关了，这个时候应该是最大流量值
						long delta = lastBytes - wifiLast;
						if (delta > 0) {
							values.put("_china_net", delta);
							values.put("_wifi_last", lastBytes);
						}
					}
				}

				values.put("_updated", System.currentTimeMillis());
				values.put("_day", today);
				db.insert("channel_day_stat", null, values);
				EvtLog.i(TAG, "insert {" + values.toString() + "} to TABLE channel_day_stat with bootCursor");
			}
		} else {
			long mobileBytes = Utils.getMobileBytes();
			long wifiBytes = Utils.getWifiBytes();
			Cursor todayCursor = db.rawQuery(
					"SELECT _id, _3g_gprs, _cmcc, _unicom, _china_net, _wifi FROM channel_day_stat WHERE _day = '"
							+ today + "' LIMIT 1", null);
			if (todayCursor.moveToFirst()) {
				// 这是device启动之后的第一个更新，但是也可能今天的记录存在
				// （原因可能是今天早些时候程序挂掉了），因此需要判断下，
				// 机器重启之后mobile 和 wifi均清零，因此，此处累加即可，
				long id = todayCursor.getLong(todayCursor.getColumnIndex("_id"));
				long gprs = todayCursor.getLong(todayCursor.getColumnIndex("_3g_gprs"));
				long cmcc = todayCursor.getLong(todayCursor.getColumnIndex("_cmcc"));
				long unicom = todayCursor.getLong(todayCursor.getColumnIndex("_unicom"));
				long telecom = todayCursor.getLong(todayCursor.getColumnIndex("_china_net"));
				long wifi = todayCursor.getLong(todayCursor.getColumnIndex("_wifi"));

				// 由于是刚启动，mobileBytes,wifiBytes 这2项值都会非常小

				ContentValues values = new ContentValues();
				switch (mNetworkFlag) {
					case FLAG_MOBILE:
						values.put("_3g_gprs", mobileBytes + gprs);
						values.put("_3g_gprs_s_boot", mobileBytes);
						break;
					case FLAG_WIFI_MOBILE:
						values.put("_cmcc", wifiBytes + cmcc);
						break;
					case FLAG_WIFI_UNICOM:
						values.put("_unicom", wifiBytes + unicom);
						break;
					case FLAG_WIFI_TELECOM:
						values.put("_china_net", wifiBytes + telecom);
						break;
					case FLAG_WIFI:
					case FLAG_NONE:
						values.put("_wifi", wifiBytes + wifi);
						break;
				}

				if (mNetworkFlag != FLAG_MOBILE && wifiBytes >= 0) {
					values.put("_wifi_last", wifiBytes);
				}
				values.put("_updated", System.currentTimeMillis());
				db.update("channel_day_stat", values, "_id = " + id, null);
			} else {
				ContentValues values = new ContentValues();
				values.put("_3g_gprs", mobileBytes);
				values.put("_3g_gprs_s_boot", mobileBytes);
				switch (mNetworkFlag) {
					case FLAG_WIFI_MOBILE:
						values.put("_cmcc", wifiBytes);
						break;
					case FLAG_WIFI_UNICOM:
						values.put("_unicom", wifiBytes);
						break;
					case FLAG_WIFI_TELECOM:
						values.put("_china_net", wifiBytes);
						break;
					case FLAG_MOBILE:
					case FLAG_WIFI:
					case FLAG_NONE:
						if (wifiBytes >= 0) {
							values.put("_wifi", wifiBytes);
							values.put("_wifi_last", wifiBytes);
						}
						break;
				}
				values.put("_updated", System.currentTimeMillis());
				values.put("_day", today);
				db.insert("channel_day_stat", null, values);

				EvtLog.i(TAG, "insert {" + values.toString()
						+ "} to TABLE channel_day_stat with todayCursor point to 0 record");
			}
			todayCursor.close();
		}
		bootCursor.close();

		if (isFirst) {
			mNotificationHandler.sendEmptyMessage(0);
		}

		mChannelDataHandler.sendEmptyMessageDelayed(0, UPDATE_CHANNEL_NETWORK_FREQUECY);
	}

	private final Handler mAppNetworkDataHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			final boolean updated = syncAppDataInDay(false);
			mPreferences.setLastSyncTime(System.currentTimeMillis());
			sendEmptyMessageDelayed(0, UPDATE_APP_NETWORK_FREQUECY);
			if (updated) {
				sendBroadcast(new Intent(EVENT_USAGE_OF_NETWORK_FOR_APPS_UPDATED));
			}
		}
	};

	/**
	 * Action for event when the usage of network for some applications changed.
	 */
	public static final String EVENT_USAGE_OF_NETWORK_FOR_APPS_UPDATED = "event_today_net_updated";

	private boolean syncAppDataInDay(boolean isFirst) {
		boolean updated = false;
		ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
		List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
		if (null == runningApps || runningApps.size() == 0) {
			return updated;
		}

		long lastSyncTime = mPreferences.getLastSyncTime();
		long lastBootTime = mPreferences.getBootTime();
		EvtLog.i(TAG, "(sync, boot) = (" + lastSyncTime + ", " + lastBootTime + ")");
		SQLiteDatabase db = NetStarApplication.getDatabase();
		db.beginTransaction();
		try {
			for (ActivityManager.RunningAppProcessInfo proc : runningApps) {
				int uid = proc.uid;
				final long bytesSentSinceBoot = Utils.getSentBytes(uid);
				final long bytesReceivedSinceBoot = Utils.getReceivedBytes(uid);
				if (bytesSentSinceBoot == 0 && bytesReceivedSinceBoot == 0) {
					continue;
				}
				String[] pkgs = proc.pkgList;
				final int len = pkgs.length;
				for (int i = 0; i < len; i++) {
					final String pkg = pkgs[i];
					final long appID = NetStarApplication.getAppId(pkg);
					final String today = Utils.getNowInDay();
					if (lastSyncTime > lastBootTime) {
						/*
						 * 上次更新数据到现在 ，期间机器没有启动过，因此各进程流量不会清零(进程停止的除外)
						 * ，更新该package的流量
						 */
						Cursor baseCursor = db.rawQuery(
								"SELECT _received, _sent, _received_since_boot, _sent_since_boot, _day, _id, _g_received, _g_sent "
										+ "FROM apps_day_stat WHERE _app_id = " + appID + " AND _updated > "
										+ lastBootTime + " ORDER BY _id DESC", null);
						if (baseCursor.moveToNext()) {
							/*
							 * 从机器启动截止现在，该pkg的流量统计存在，因此更新它
							 */

							long lastReceivedSinceBoot = baseCursor.getLong(baseCursor
									.getColumnIndex("_received_since_boot"));
							long lastSentSinceBoot = baseCursor.getLong(baseCursor.getColumnIndex("_sent_since_boot"));

							long deltaReceived = bytesReceivedSinceBoot - lastReceivedSinceBoot;
							long deltaSent = bytesSentSinceBoot - lastSentSinceBoot;
							if (0 == deltaReceived && 0 == deltaSent) {
								continue;
							}
							updated = true;

							long todayReceived = baseCursor.getLong(baseCursor.getColumnIndex("_received"))
									+ deltaReceived;
							long todaySent = baseCursor.getLong(baseCursor.getColumnIndex("_sent")) + deltaSent;

							String day = baseCursor.getString(baseCursor.getColumnIndex("_day"));
							if (day.equals(today)) {
								EvtLog.i(TAG, "update today's record for " + pkg);
								ContentValues values = new ContentValues();
								values.put("_received", todayReceived);
								values.put("_sent", todaySent);
								values.put("_received_since_boot", bytesReceivedSinceBoot);
								values.put("_sent_since_boot", bytesSentSinceBoot);
								values.put("_updated", System.currentTimeMillis());
								if (mNetworkFlag == FLAG_MOBILE) {
									long todayGPRSReceived = baseCursor.getLong(baseCursor
											.getColumnIndex("_g_received")) + deltaReceived;
									long todayGPRSSent = baseCursor.getLong(baseCursor.getColumnIndex("_g_sent"))
											+ deltaSent;
									values.put("_g_received", todayGPRSReceived);
									values.put("_g_sent", todayGPRSSent);
								}
								long id = baseCursor.getLong(baseCursor.getColumnIndex("_id"));
								db.update("apps_day_stat", values, "_id = " + id, null);
							} else {
								/*
								 * 这可能是一个凌晨00点00分15秒做的同步，发现上次更新的数据是昨天的，今天的统计清零
								 * 我们不需要这么精准的统计，因此只需要把流量差留给今天就好
								 */
								EvtLog.i(TAG, "insert new day record for " + pkg);

								ContentValues values = new ContentValues();
								values.put("_app_id", appID);
								values.put("_received", deltaReceived);
								values.put("_sent", deltaSent);
								values.put("_received_since_boot", bytesReceivedSinceBoot);
								values.put("_sent_since_boot", bytesSentSinceBoot);
								values.put("_day", today);
								values.put("_updated", System.currentTimeMillis());
								if (mNetworkFlag == FLAG_MOBILE) {
									values.put("_g_received", deltaReceived);
									values.put("_g_sent", deltaSent);
								}
								db.insert("apps_day_stat", null, values);
							}
						} else {
							/*
							 * 从设备启动到现在，还没有更新过该pkg的流量信息，但是可能存在今天的流量信息
							 */
							Cursor c = db.rawQuery(
									"SELECT _received, _sent, _id, _g_received, _g_sent FROM apps_day_stat "
											+ "WHERE _app_id = " + appID + " AND _day = '" + today + "'", null);
							if (c.moveToNext()) {
								EvtLog.i(TAG, "虽然重启了，但是今天的流量依然存在，更新之, " + pkg);
								long lastReceived = c.getLong(c.getColumnIndex("_received"));
								long lastSent = c.getLong(c.getColumnIndex("_sent"));

								long todayReceived = lastReceived + bytesReceivedSinceBoot;
								long todaySent = lastSent + bytesSentSinceBoot;

								ContentValues values = new ContentValues();
								values.put("_received", todayReceived);
								values.put("_sent", todaySent);
								values.put("_received_since_boot", bytesReceivedSinceBoot);
								values.put("_sent_since_boot", bytesSentSinceBoot);
								values.put("_updated", System.currentTimeMillis());
								if (mNetworkFlag == FLAG_MOBILE) {
									long todayGPRSReceived = c.getLong(c.getColumnIndex("_g_received"))
											+ bytesReceivedSinceBoot;
									long todayGPRSSent = c.getLong(c.getColumnIndex("_g_sent")) + bytesSentSinceBoot;
									values.put("_g_received", todayGPRSReceived);
									values.put("_g_sent", todayGPRSSent);
								}
								long id = c.getLong(c.getColumnIndex("_id"));
								db.update("apps_day_stat", values, "_id = " + id, null);

							} else {
								EvtLog.i(TAG, "no existed network statistics for pkg " + pkg + " since boot");
								ContentValues values = new ContentValues();
								values.put("_app_id", appID);
								values.put("_received", bytesReceivedSinceBoot);
								values.put("_sent", bytesSentSinceBoot);
								values.put("_received_since_boot", bytesReceivedSinceBoot);
								values.put("_sent_since_boot", bytesSentSinceBoot);
								values.put("_updated", System.currentTimeMillis());
								values.put("_day", today);
								if (mNetworkFlag == FLAG_MOBILE) {
									// Even the current network is mobile, we
									// still can not compute bytesReceived and
									// bytesSent to this application as 3G/GPRS,
									// because WIFI can make this possible too,
									// we just put 0.0..0...
								}
								db.insert("apps_day_stat", null, values);
							}

							c.close();
						}
						baseCursor.close();
					} else {
						/*
						 * This is the first synchronizing work since boot.
						 */
						Cursor cur = db.rawQuery("SELECT _id, _received, _sent FROM apps_day_stat WHERE _app_id = "
								+ appID + " AND _day = '" + today + "'", null);
						if (cur.moveToNext()) {
							EvtLog.i(TAG, "---booted! update today's record for " + pkg);
							long todayReceived = cur.getLong(cur.getColumnIndex("_received")) + bytesReceivedSinceBoot;
							long todaySent = cur.getLong(cur.getColumnIndex("_sent")) + bytesSentSinceBoot;

							ContentValues values = new ContentValues();
							values.put("_received", todayReceived);
							values.put("_sent", todaySent);
							values.put("_received_since_boot", bytesReceivedSinceBoot);
							values.put("_sent_since_boot", bytesSentSinceBoot);
							values.put("_updated", System.currentTimeMillis());
							if (mNetworkFlag == FLAG_MOBILE) {
								// long todayGPRSReceived = cur.getLong(cur
								// .getColumnIndex("_g_received"))
								// + bytesReceivedSinceBoot;
								// long todayGPRSSent = cur.getLong(cur
								// .getColumnIndex("_g_sent"))
								// + bytesSentSinceBoot;
								// values.put("_g_received", todayGPRSReceived);
								// values.put("_g_sent", todayGPRSSent);
							}
							long id = cur.getLong(cur.getColumnIndex("_id"));
							db.update("apps_day_stat", values, "_id = " + id, null);
						} else {
							EvtLog.i(TAG, "---booted! new record for package " + pkg + " on day " + today);

							ContentValues values = new ContentValues();
							values.put("_app_id", appID);
							values.put("_received", bytesReceivedSinceBoot);
							values.put("_sent", bytesSentSinceBoot);
							values.put("_received_since_boot", bytesReceivedSinceBoot);
							values.put("_sent_since_boot", bytesSentSinceBoot);
							values.put("_updated", System.currentTimeMillis());
							values.put("_day", today);
							if (mNetworkFlag == FLAG_MOBILE) {
								// Because this is the first time
								// values.put("_g_received",
								// bytesReceivedSinceBoot);
								// values.put("_g_sent", bytesSentSinceBoot);
							}
							db.insert("apps_day_stat", null, values);
						}
						cur.close();
					}

				}
			}
			db.setTransactionSuccessful();
		} finally {
			db.endTransaction();
		}
		return updated;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		if (null != mNetworkReceiver) {
			unregisterReceiver(mNetworkReceiver);
			mNetworkReceiver = null;
		}
		if (null != mChannelUpdateReceiver) {
			unregisterReceiver(mChannelUpdateReceiver);
			mChannelUpdateReceiver = null;
		}
		// unregisterReceiver(mSmsReceiver);
		mChannelTimerHandler.removeMessages(0);
		mUpdateHandler.removeMessages(0);
		mChannelDataHandler.removeMessages(0);
		mAppNetworkDataHandler.removeMessages(0);
		mNotificationHandler.removeMessages(0);
		mSyncServerHandler.removeMessages(0);
		mNotificationManager.cancel(ID_NOTIFICATION);

		mProcessWatcher.stopWatch();
		/**
		 * We should not get the service stopped.
		 */
		startService(new Intent(this, NetService.class));
	}

	private static final class ChannelInfo {

		private String mChannelName;
		public boolean newlyConnected;
		public long lastBytes = -1;

		public ChannelInfo(String name) {
			mChannelName = name;
		}

		public void reset() {
			newlyConnected = false;
			lastBytes = -1;
		}

		@Override
		public String toString() {
			return "{name = " + mChannelName + ", lastBytes = " + lastBytes + ", newlyConnected = " + newlyConnected
					+ "}";
		}
	}
}
